#include <libdswutility/dswwatchdog.h>

#define CHECK_WATCHDOG_TIMEOUT 10
#define WATCHDOG_TIMEOUT 30
#define WDT_DEVICE_FILE "/dev/watchdog"

CDswwatchdog::CDswwatchdog(LPST_ENV_T pEnv)
: CDswbase(pEnv)
, m_nWatchDogFd(-1)
, m_nWatchDogThreadID(INVALID_PTHREAD_ID)
{
	int nTimeout;
	LOG4CPLUS_DEBUG(log_dsw, "Create CDswwatchdog class!");

	m_nWatchDogTask.ev = NULL;
	m_nWatchDogFd = open(WDT_DEVICE_FILE, O_RDWR);
	if (!m_nWatchDogFd){
		LOG4CPLUS_ERROR(log_dsw, "Open watchdog device [ " << WDT_DEVICE_FILE << " ] failed!");
		m_nWatchDogFd = -1;
	}
	else{
		ioctl(m_nWatchDogFd, WDIOS_ENABLECARD, 0);

		ioctl(m_nWatchDogFd, WDIOC_GETTIMEOUT, &nTimeout);
		LOG4CPLUS_DEBUG(log_dsw, "Default watchdog timeout = " << nTimeout << " Sec.");
		nTimeout = WATCHDOG_TIMEOUT;
		ioctl(m_nWatchDogFd, WDIOC_SETTIMEOUT, &nTimeout);
		ioctl(m_nWatchDogFd, WDIOC_GETTIMEOUT, &nTimeout);
		if (nTimeout != WATCHDOG_TIMEOUT)
			LOG4CPLUS_ERROR(log_dsw, "Set new timeout error!");
		else
			LOG4CPLUS_DEBUG(log_dsw, "Now watchdog timeout = " << nTimeout << " Sec.");
		ioctl(m_nWatchDogFd, WDIOC_KEEPALIVE, 0);
	}
	m_nWatchDogTask.ev = NULL;
	CREATE_EV(m_nWatchDogTask, CHECK_WATCHDOG_TIMEOUT, 0, pEnv->pEvBase, CDswwatchdog::cbWatchDogTask, this);
//	pthread_create(&m_nWatchDogThreadID, NULL, CDswwatchdog::cbWatchDogThreadFunc, this);
}

CDswwatchdog::~CDswwatchdog()
{
	CLEAR_EV(m_nWatchDogTask);
	if (m_nWatchDogThreadID != INVALID_PTHREAD_ID)
		pthread_join(m_nWatchDogThreadID, NULL);
	if (m_nWatchDogFd != -1){
		ioctl(m_nWatchDogFd, WDIOS_DISABLECARD, 0);
		close(m_nWatchDogFd);
	}
	LOG4CPLUS_DEBUG(log_dsw, "Destroy CDswwatchdog class!");
}

void CDswwatchdog::WatchDogThreadFunc()
{
	time_t nStartTM = 0;
	while(!m_pEnv->bExit){
		if (abs(nStartTM - time(NULL)) > 5){
			nStartTM = time(NULL);
			if (m_nWatchDogFd != -1)
				ioctl(m_nWatchDogFd, WDIOC_KEEPALIVE, 0);
		}
		usleep(1000 * 100);
	}
}

void CDswwatchdog::WatchDogTask(int fd, short events)
{
	if (m_nWatchDogFd == -1)
		goto END_WATCHDOG;
	ioctl(m_nWatchDogFd, WDIOC_KEEPALIVE, 0);
END_WATCHDOG:
	TRIG_EV(m_nWatchDogTask, CHECK_WATCHDOG_TIMEOUT, 0)
}

int CDswwatchdog::OnMessage(EN_MSG_TYPE nMsgType, void* pParam)
{
	switch(nMsgType){
	case PMSG_SET_REBOOT:
		if (m_nWatchDogFd != -1){
			int nTimeout = CHECK_WATCHDOG_TIMEOUT - 2;
			LOG4CPLUS_DEBUG(log_dsw, "Reboot system after " << CHECK_WATCHDOG_TIMEOUT - 2 << " seconds.");
			ioctl(m_nWatchDogFd, WDIOC_SETTIMEOUT, &nTimeout);
			CLEAR_EV(m_nWatchDogTask);
		}
		break;
	}
}

